﻿namespace ChinaUnicom.Web
{
    using System;
    using System.Linq;
    using System.Net;
    using System.Text;
    using ChinaUnicom.Exceptions;
    using System.Text.RegularExpressions;

    class WebRequestOperation : IOperation
    {
        static object AutoLoginLocker = new object();

        // Windows Phone OS 7.5 IE 9.0
        const string UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; SGH-i917)";

        const string Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
        const string ContentType = "application/x-www-form-urlencoded";
        const string KeepAlive = "keep-alive";

        const string BaseUrl = "http://mob.10010.com/";

        const string LoginUrl = "http://mob.10010.com/mini/login.do?type=local";
        const string LoginPostParameters = "mobile={0}&password={1}&imgCode={2}";

        const string AutoLoginUrl = "http://mob.10010.com/mini/operationservice/beforeHistoryBusinessBL.do";

        const string LogoutUrl = "http://mob.10010.com/mini/loginOut.do";
        const string UserInfoUrl = "http://mob.10010.com/mini/operationservice/getUserinfo.do";
        const string RealFeeUrl = "http://mob.10010.com/mini/query/queryRealFee.do";
        const string PackageFlowLeftUrl = "http://mob.10010.com/mini/operationservice/queryOcsPackageFlowLeft.do";
        const string ImageStreamUrlTemplate = "http://mob.10010.com/mini/sinova.gif?width=72&height=21&r={0}";
        // 历史账单
        const string FeeHistoryUrlTemplate = "http://mob.10010.com/mini/query/queryRealFeeHistroy.do?month={0:D4}{1:D2}";
        // 积分查询
        const string QueryPointUrl = "http://mob.10010.com/mini/points/queryPoint.do";
        // 产品套餐
        const string QueryProductUrl = "http://mob.10010.com/mini/operationservice/queryOcsCurrentPackage.do";

        const string SessionUrlTemplate = "http://mob.10010.com/mini/secureLogin.do?secure={0}";

        public DateTime LastUpdated { get; private set; }

        Uri SessionUri;
        CookieContainer cookies;
        RequestCreator creator;

        public WebRequestOperation()
        {
            SessionUri = null;
            cookies = new CookieContainer();
            if (Authentication.Current.Authorized)
            {
                cookies.Add(new Uri(BaseUrl), Authentication.Current.Cookie);
            }

            creator = new RequestCreator(this);
        }

        void GenerateSecurity(Action<HttpStatus> callback)
        {
            if (SessionUri != null)
            {
                callback.TryCall(null);
                return;
            }

            // secureLogin\.do\?secure=[\s|\d]+
            var request = creator.Create(new Uri(BaseUrl));
            request.Execute(s =>
            {
                if (s.Status == WebExceptionStatus.Success)
                {
                    Regex r = new Regex(@"secureLogin\.do\?secure=\w+");
                    var sourceMatch = r.Match(s.Result);
                    if (sourceMatch.Success)
                    {
                        SessionUri = new Uri(string.Format(SessionUrlTemplate, sourceMatch.Value.Substring("secureLogin.do?secure=".Length)));
                    }

                    if (SessionUri == null)
                    {
                        s.Status = WebExceptionStatus.TrustFailure;
                        s.Exception = new Exception("验证失败！");
                    }
                }

                callback.TryCall(s);
            });
        }

        public void CreateSession(Action<HttpStatus> callback)
        {
            GenerateSecurity(s =>
            {
                if (s != null && s.Status != WebExceptionStatus.Success)
                {
                    callback.TryCall(s);
                    return;
                }

                var request = creator.Create(SessionUri);
                request.Execute(callback);
            });
        }

        public void AutoLogin(Action<HttpStatus> callback)
        {
            if (!Authentication.Current.Signed)
                lock (AutoLoginLocker)
                    if (!Authentication.Current.Signed)
                    {
                        var request = creator.Create(new Uri(AutoLoginUrl));
                        request.Execute(callback);
                    }
        }

        public void Login(string mobile, string password, string imgcode, Action<HttpStatus> callback)
        {
            HttpWebRequest request = creator.Create(new Uri(LoginUrl), HttpMethod.POST);

            // post data.
            request.BeginGetRequestStream(s =>
            {
                var stream = request.EndGetRequestStream(s);
                var buffer = Encoding.UTF8.GetBytes(string.Format(LoginPostParameters, mobile, password, imgcode));
                stream.Write(buffer, 0, buffer.Length);
                stream.Close();

                request.Execute(x =>
                {
                    var cookie = cookies.GetCookies(SessionUri).Cast<Cookie>().FirstOrDefault(c => c.Name == Authentication.Key);
                    if (cookie != null)
                    {
                        Authentication.Current.Register(cookie.Value);
                    }
                    else
                    {
                        x.Exception = new UnicomException(Factory.Parser.Failed(x.Result));
                        x.Status = WebExceptionStatus.TrustFailure;
                    }

                    callback.TryCall(x);
                });

            }, null);
        }

        public void Logout()
        {
            this.cookies = new CookieContainer();
            SessionUri = null;
        }

        public void RequestUserInfo(Action<HttpStatus> callback)
        {
            var request = creator.Create(new Uri(UserInfoUrl));
            request.Execute(callback);
        }

        public void RequestFeeInfo(Action<HttpStatus> callback)
        {
            var request = creator.Create(new Uri(RealFeeUrl));
            request.Execute(callback);
        }

        public void RequestPackageInfo(Action<HttpStatus> callback)
        {
            var request = creator.Create(new Uri(PackageFlowLeftUrl));
            request.Execute(callback);
        }

        public void RequestCodeImage(Action<HttpStatus> callback)
        {
            int r = new Random((int)DateTime.Now.Ticks).Next();
            var request = creator.Create(new Uri(string.Format(ImageStreamUrlTemplate, r)));
            request.Execute(callback);
        }

        public void RequestFeeHistory(int year, int month, Action<HttpStatus> callback)
        {
            var request = creator.Create(new Uri(string.Format(FeeHistoryUrlTemplate, year, month)));
            request.Execute(callback);
        }

        public void RequestPoint(Action<HttpStatus> callback)
        {
            var request = creator.Create(new Uri(QueryPointUrl));
            request.Execute(callback);
        }

        public void RequestProduct(Action<HttpStatus> callback)
        {
            var request = creator.Create(new Uri(QueryProductUrl));
            request.Execute(callback);
        }

        class RequestCreator
        {
            WebRequestOperation operation;
            public RequestCreator(WebRequestOperation operation)
            {
                this.operation = operation;
            }

            public HttpWebRequest Create(Uri uri, HttpMethod method = HttpMethod.GET)
            {
                // Create a HttpWebrequest object to the desired URL.
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);

                request.Method = method.Named();
                request.UserAgent = UserAgent;
                request.Accept = Accept;
                request.Headers[HttpRequestHeader.Connection] = KeepAlive;
                request.CookieContainer = operation.cookies;
                if (method == HttpMethod.POST)
                {
                    request.ContentType = ContentType;
                }

                operation.LastUpdated = DateTime.Now;

                return request;
            }
        }
    }
}
